package custom;

import java.util.ArrayList;


public class BallCollection extends ArrayList<Ball> {

	protected void updateInformation(double deltaT) {
		for (Ball b : this) {
			b.tick(deltaT);
		}

		// Check for collisions between all the balls.
		for(Ball b : this) {
			for(Ball b2 : this) {
				if(doWeIntersect(b, b2)) {
	                double dotProduct = (b.getX()-b2.getX())*(b2.getVx() - b.getVx()) + (b.getY()-b2.getY())*(b2.getVy() - b.getVy());
	                if(dotProduct > 0)
	                	collide(b, b2);
				}
			}
		}
	}

	private void collide(Ball firstBall, Ball secondBall) {
		
		// Calculate the theta angle of the triangle between the two balls centers
		double thetaAngle = Math.atan2(secondBall.getY() - firstBall.getY(), secondBall.getX() - firstBall.getX());

		// Rotate the Balls centerpoints theta angles from (X, Y) to (P, N) plane. 
		double[] result = rotate(firstBall.getVx(), firstBall.getVy(), thetaAngle);
	    double firstBallvP = result[0];
	    double firstBallvN = result[1];
	    result = rotate(secondBall.getVx(), secondBall.getVy(), thetaAngle);
	    double secondBallvP = result[0];
	    double secondBallvN = result[1];
	     	    
	    // Calculate the new velocity vectors in the new plane.
	    double diffMass = firstBall.getMass() - secondBall.getMass();
	    double sumMass = firstBall.getMass() + secondBall.getMass();
	    
	    double firstBallvPAfter;
	    double secondBallvPAfter;
		if (diffMass != 0) {
			firstBallvPAfter = (2.0 * secondBall.getMass() * secondBallvP + diffMass * firstBallvP) / sumMass;
			secondBallvPAfter = (2.0 * firstBall.getMass() * firstBallvP + diffMass * secondBallvP) / sumMass;
		} else {
			firstBallvPAfter = secondBallvP;
			secondBallvPAfter = firstBallvP;
		}

	    // There are no change in the N
	    double firstBallvNAfter = firstBallvN;
	    double secondBallvNAfter = secondBallvN;

	    // Rotate the centerpoints back theta angles.
	    result = rotate(firstBallvPAfter, firstBallvNAfter, -thetaAngle);
	    firstBall.setVx(result[0]);
	    firstBall.setVy(result[1]);
	    result = rotate(secondBallvPAfter, secondBallvNAfter, -thetaAngle);
	    secondBall.setVx(result[0]);
	    secondBall.setVy(result[1]);   
	}

	 /**
	  * Performs a rotation in two dimensions using the following formula:
	  * [x] * [cos*angle, sin*angle]  = [x*cos*angle+y*sin*angle]
	  * [y]   [-sin*angle, cos*angle]	[-x*sin*angle+y*cos*angle]
	  * @param x Original x-coordinate.
	  * @param y Original y-coordinate.
	  * @param angle The angle to rotate around.
	  * @return A vector with the new coordinates in [X, Y] form.
	  */
	private static double[] rotate(double x, double y, double angle) {
		double[] rotateResult = new double[2];
	    rotateResult[0] = x * Math.cos(angle) + y * Math.sin(angle);
	    rotateResult[1] = -x * Math.sin(angle) + y * Math.cos(angle);
	    return rotateResult;
	 	}
	
	/**
	 * Method that checks if two balls intersect.
	 * @param firstBall
	 * @param secondBall
	 * @return True if they intersect, false otherwise.
	 */
	private boolean doWeIntersect(Ball firstBall, Ball secondBall) {
		if(!firstBall.equals(secondBall)) {
			if ((Math.pow(firstBall.getX()-secondBall.getX(), 2) + Math.pow(firstBall.getY()-secondBall.getY(), 2)) <= (Math.pow(firstBall.getR()+secondBall.getR(), 2))) {
				return true;
			}
		}
		return false;
	}
}